#pragma once

#include <iostream>
#include <string>
#include <cstdint>
#include <thread>

#include <sys/wait.h>
#include <unistd.h>

#include "Socket.hpp"
#include "agreement.pb.h"

using namespace std;
using namespace SocketModule;

class TcpServer
{
    static const uint16_t default_port = 0;
    static const uint16_t default_read_size = 4096;

    static const string default_sep; // 默认分割符

    typedef function<bool(const int, const char, const int, int &)> calc_handle_t; // 计算器

    // 报文格式: 有效载荷长度\r\n有效载荷
    // 缓冲区可能格式：有效载荷长度\r\n有效载荷有效载荷长度\r\n有效载荷有效载荷长度\r...

    bool isFull(string &in, string &sk) // 判断报文是否完整，如果完整就取出一份有效载荷放入sk中
    {
        int pos = in.find(default_sep); // 分割报头和有效载荷

        if (pos == string::npos) // 如果没找到  分割报头和有效载荷的分割符
        {
            return false; // 报头不完整
        }

        // 取出有效载荷的长度
        int pa_size = stoi(in.substr(0, pos));

        // 判断有效载荷是否完整
        if (in.size() - (pos + default_sep.size()) < pa_size)
        {
            return false; // 有效载荷不完整
        }

        // 报文完整，取出有效载荷
        int start = pos + default_sep.size();
        int end = start + pa_size;
        sk = in.substr(start, end); // 取出有效载荷

        // 清除缓冲区中被拿走的报文
        in.erase(0, end);

        return true;
    }

    void HandleRequeat(SockPtr sock) // 处理请求
    {
        string inbuf; // 用户级接收缓冲区
        string outbuf; //  用户级发送缓冲区
        while (true)
        {
            // 读取请求
            string in;
            int n = sock->Recv(in);
            if (n > 0)
            {
                inbuf += in;
            }
            else if (n == 0)
            {
                LOG(LogLevel::DEBUG) << "客户端退出" << in;
                sock->Close(); // 关闭fd
                return;        // 线程退出
            }
            else
            {
                LOG(LogLevel::ERROR) << "recv error" << in;
                return;
            }

            string sk;             // 一份完整报文
            while (isFull(in, sk)) // 如果取出一份完整报文
            {
                // 拿到一份有效载荷

                // 解析请求
                Request requ;
                requ.ParseFromString(sk); // 反序列化

                int result = 0;
                bool istrust = false;
                if (_calc != nullptr)
                {
                    // 调用计算机注册进来的函数进行计算
                    istrust = _calc(requ._left(), (char)requ._operator(), requ._right(), result);
                    LOG(LogLevel::DEBUG) << requ._left() << (char)requ._operator() << requ._right()
                                         << "=" << result << ", 结果是否可信：" << istrust;
                }

                // 构建响应
                Response resp;
                resp.set__result(result);
                resp.set__is_trust(istrust);

                // 序列化
                string info;
                resp.SerializeToString(&info);

                // 添加应用层报头:有效载荷长度\r\n
                string out = to_string(info.size()) + "\r\n";
                out += info;

                outbuf+=out;

                sk.clear();
            }

            if(outbuf.empty())//发送缓冲区为空，就再去recv
            {
                continue;
            }

            // 给客户端返回响应报文
            n = sock->Send(outbuf);
            if (n > 0)
            {
                outbuf.clear();//清空已经发送过的数据
            }
            else if (n == 0)
            {
                LOG(LogLevel::DEBUG) << "客户端退出" << in;
                sock->Close(); // 关闭fd
                return;        // 线程退出
            }
            else
            {
                LOG(LogLevel::ERROR) << "send error" << in;
                continue;
            }
        }
    }

public:
    TcpServer(uint16_t port = default_port)
        : _port(port),
          _listensocket(make_shared<TcpSocket>(port)),
          _isrunning(false),
          _calc(nullptr)
    {
    }
    void InitServer()
    {
        // 创建lisentsocket
        _listensocket->BuildSocket(SockType::LISTEN_SOCK);
    }
    void Registration(calc_handle_t calc) // 注册
    {
        _calc = calc;
    }
    void Start()
    {
        _mutex.lock();          // 保护_isrunning
        if (_isrunning == true) // 不允许重复启动
        {
            return;
        }
        _isrunning = true;

        while (_isrunning)
        {
            _mutex.unlock();
            // 主线程负责获取新连接
            uint32_t client_ip;
            uint16_t client_port;
            SockPtr sock = _listensocket->Accept(client_ip, client_port);
            if (sock == nullptr) // 获取新连接失败
            {
                continue;
            }

            // 连接管理--多线程版本
            thread t([this, sock]()
                     { this->HandleRequeat(sock); });
            t.detach(); // 线程分离

            //---------------------------//

            // 连接管理--多进程版本
            /*int n = fork();
            if (n == 0) // 子进程
            {
                // 创建孙子进程，并让孙子进程变成孤儿进程
                // 这样就不需要主动等待回收了
                if (fork() > 0)
                {
                    // 子进程退出
                    exit(0);
                }

                // 孙子进程去处理请求
                HandleRequeat(sock);
                // 孙子进程退出
                exit(0);
            }
            // 回收退出的子进程
            sock->Close(); // 父进程关闭fd，防止fd泄漏

            int r = waitpid(n, nullptr, 0);
            if (r < 0)
            {
                LOG(LogLevel::ERROR) << "waitpid error";
            }*/
        }
    }
    void Stop()
    {
        lock_guard<mutex> lock(_mutex); // 保护_isrunning
        _isrunning = false;
    }
    ~TcpServer()
    {
        _listensocket->Close();
    }

private:
    uint16_t _port;
    SockPtr _listensocket;
    bool _isrunning;
    calc_handle_t _calc;
    mutex _mutex;
};

const string TcpServer::default_sep = "\r\n";
